#include "threadpool.h"
#include "tools.h"
#include "tcp.h"
#include "linkedlist.h"

int epfd;
int exitpipe[2];

UserList* userList;

void sigfunc(int num) ;
 
int main(int argc,char* argv[])
{
    //./server ./conf/server.conf
    ARGS_CHECK(argc,2);

    //加载服务器配置
    char ip[16];
    memset(ip,'\0',sizeof(ip));
    uint16_t port;
    int threadNum;
    load_config_file(argv[1], ip, &port, &threadNum);
    printf("ip = %s, port = %d, threadNum = %d\n", ip, port, threadNum);

	signal(SIGUSR1, sigfunc);//10号信号
    
    pipe(exitpipe);//创建退出的管道

	pid_t pid = fork();
	if(pid > 0) {
		close(exitpipe[0]);
		wait(NULL);
		exit(0);
	}
	
    //子进程
	close(exitpipe[1]);
	
    thread_pool_t threadpool;
	threadpoolInit(&threadpool, threadNum);
	threadpoolStart(&threadpool);

	//2. 创建TCP的监听套接字listenfd
	int listenfd = tcpServerInit(ip, port);

	//3. 创建epoll的实例, 并注册(监听)相应文件描述符上的事件
	epfd =  epollCreate();
	epollAddReadEvent(epfd, listenfd);
	epollAddReadEvent(epfd, exitpipe[0]);

	struct epoll_event * pevtList = (struct epoll_event*)
		calloc(MAXCONNS, sizeof(struct epoll_event));
	
    //初始化已经登录的用户链表
    userList=create_list();
    
    train_t train;

    char recvbuf[NETBUFSIZE];
	int nready;
	while(1) {
		do {
			//4. epoll等待事件就绪
			nready = epoll_wait(epfd, pevtList, MAXCONNS, 5000);
		
        }while(-1 == nready && errno == EINTR);

		if(0 == nready) {
			printf(">> epoll timeout.\n");
			continue;
		} else if(-1 == nready) {
			perror("epoll_wait");
			return EXIT_FAILURE;
		} else {
            //nready > 0
			for(int i = 0; i < nready; ++i) {
				int fd = pevtList[i].data.fd;
				if(fd == listenfd) {//5. 客户端到来的处理
					int peerfd = accept(listenfd, NULL, NULL);
					if(peerfd < 0) {
						perror("accept");
					}
                    
                    memset(train.data, '\0', NETBUFSIZE);
                    strcpy(train.data, "-------------------登录注册界面-------------------\n1. 登录\n2. 注册\n请输入'1'或'2':");
					train.length=getLength(train.data);
                    sendn(peerfd, &train, 8+train.length);
                    
                    epollAddReadEvent(epfd, peerfd);
                    printf("accept a new conn, peerfd: %d\n", peerfd);

                    log_client("accpet a new conn");

				} else if(fd == exitpipe[0]) {
					char exitflag;
					read(exitpipe[0], &exitflag, 1);
					printf("parent process ready to exit.\n");
					//收到退出的通知之后，子线程要逐步退出
					queueWakeup(&threadpool.queue);
					for(int j = 0; j < threadNum; ++j) {
						pthread_join(threadpool.threads[j], NULL);
					}
					printf("parent process pool exit\n");
					threadpoolDestroy(&threadpool);
					exit(0);
                
                } else if(pevtList[i].events & EPOLLIN){
                    memset(recvbuf,'\0',NETBUFSIZE);
                    //接收客户端的数据
                    recv(fd,recvbuf, NETBUFSIZE, 0);
                    
                    //判断是那种类型任务
                    if(strcmp(recvbuf,"1\n")==0){
                        //register
                        // 删除监听
                        epollDelEvent(epfd, fd);
					    
                        //让fd,taskType,command加入任务队列
                        taskEnqueue(&threadpool.queue, fd, TASK_LOGIN, recvbuf);
                        
                    }else if(strcmp(recvbuf,"2\n")==0){
                        //login
                        // 删除监听
                        epollDelEvent(epfd, fd);
                        
                        //让fd,taskType,command加入任务队列
					    taskEnqueue(&threadpool.queue, fd, TASK_REGISTER, recvbuf);
                    
                    }else{
                        //command
                        // 删除监听
                        epollDelEvent(epfd, fd);
                        
                        //让fd,taskType,command加入任务队列
					    printf("have command task: %s\n", recvbuf);
                        taskEnqueue(&threadpool.queue, fd, TASK_COMMAND, recvbuf);
                        
                    }
                }
            }
        }
    }
	
    free(pevtList); 
	close(listenfd);
	close(epfd);
	return 0;
}

void sigfunc(int num) 
{
	printf("sig %d is coming\n", num);
	//通过管道通知父进程退出
	char ch = 1;
	write(exitpipe[1], &ch, 1);
}


